﻿#pragma once
// Inner Fire 游戏引擎库
// MESH的创建器
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 用于生成简单的模型。根据《DirectX12游戏开发实战》中的工具类修改。
// 原作者：Frank Luna
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-19

#include <dx_core/dx_core.h>
#include <vector>

namespace ifire {

class GeometryGenerator {
public:
  using uint16 = std::uint16_t;
  using uint32 = std::uint32_t;

  struct Vertex {
    XMFLOAT3 Position;
    XMFLOAT3 Normal;
    XMFLOAT3 TangentU;
    XMFLOAT2 TexC;

    Vertex() {}
    Vertex(const XMFLOAT3& _position, const XMFLOAT3& _normal,
        const XMFLOAT3& _tangent, const XMFLOAT2& _texcoord)
        : Position(_position)
        , Normal(_normal)
        , TangentU(_tangent)
        , TexC(_texcoord) {}
    Vertex(float px, float py, float pz, // Position
        float nx, float ny, float nz,    // Normal
        float tx, float ty, float tz,    // Tangent
        float u, float v)                // Texcoord
        : Position(px, py, pz)
        , Normal(nx, ny, nz)
        , TangentU(tz, ty, tz)
        , TexC(u, v) {}
  };

  struct MeshData {
    std::vector<Vertex> Vertices;
    std::vector<uint32> Indices32;

    std::vector<uint16>& GetIndices16() {
      if (indices16.empty()) {
        indices16.resize(Indices32.size());
        for (size_t i = 0; i < Indices32.size(); i++) {
          indices16[i] = static_cast<uint16>(Indices32[i]);
        }
      }
      return indices16;
    }

    void ComputeNormal();

  private:
    std::vector<uint16> indices16;
  };

  static void ComputeAvgNormal(
      std::vector<Vertex>& vertices, const std::vector<uint32>& indices);
  // 生成柱状体
  MeshData CreateCylinder(float bottom_radius, float top_radius, float height,
      uint32 slice_count, uint32 stack_count);
  // 生成柱状体的顶部
  void BuildCylinderTopCap(float bottom_radius, float top_radius, float height,
      uint32 slice_count, uint32 stack_count, MeshData& mesh);
  // 生成柱状体的底部
  void BuildCylinderBottomCap(float bottom_radius, float top_radius,
      float height, uint32 slice_count, uint32 stack_count, MeshData& mesh);

  // 生成球体网格
  MeshData CreateSphere(float radius, uint32 slice_count, uint32 stack_count);

  // 生成几何球体
  MeshData CreateGeoshpere(float radius, uint32 sub_divisions);
  // 生成一个立方体
  MeshData CreateBox(
      float width, float height, float depth, uint32 sub_divisions);
  // 生成一个网格
  MeshData CreateGrid(float width, float depth, uint32 m, uint32 n);
  // 生成一个面片
  MeshData CreateQuad(float x, float y, float width, float height, float depth);

private:
  void Subdivide(MeshData& mesh);
  // 求得两个顶点的中点
  Vertex MidPoint(const Vertex& v0, const Vertex& v1);
};

} // namespace ifire